package com.education.platform.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.education.platform.common.ResultCode;
import com.education.platform.entity.AuditLog;
import com.education.platform.exception.BusinessException;
import com.education.platform.mapper.AuditLogMapper;
import com.education.platform.service.AuditLogService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 审计日志服务实现类
 *
 * @author education-platform
 * @since 2024-09-27
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AuditLogServiceImpl implements AuditLogService {

    private final AuditLogMapper auditLogMapper;

    @Override
    @Transactional
    public void log(String action, String targetType, Long targetId, Object oldValue, Object newValue, String remark) {
        try {
            AuditLog auditLog = new AuditLog();

            // 获取当前管理员ID
            if (StpUtil.isLogin()) {
                auditLog.setAdminId(StpUtil.getLoginIdAsLong());
            }

            auditLog.setAction(action);
            auditLog.setTargetType(targetType);
            auditLog.setTargetId(targetId);

            // 序列化旧值和新值
            if (oldValue != null) {
                auditLog.setOldValue(JSONUtil.toJsonStr(oldValue));
            }
            if (newValue != null) {
                auditLog.setNewValue(JSONUtil.toJsonStr(newValue));
            }

            auditLog.setRemark(remark);

            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                auditLog.setIp(getClientIp(request));
                auditLog.setUserAgent(request.getHeader("User-Agent"));
            }

            auditLogMapper.insert(auditLog);
            log.debug("记录审计日志成功: {}", action);
        } catch (Exception e) {
            log.error("记录审计日志失败", e);
        }
    }

    @Override
    public AuditLog getAuditLogById(Long id) {
        AuditLog auditLog = auditLogMapper.selectById(id);
        if (auditLog == null) {
            throw new BusinessException(ResultCode.NOT_FOUND);
        }
        return auditLog;
    }

    @Override
    public IPage<AuditLog> getAuditLogPage(Page<AuditLog> page, Long adminId, String action,
                                           String targetType, LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogMapper.selectAuditLogPageWithAdmin(page, adminId, action, targetType, startTime, endTime);
    }

    @Override
    public List<AuditLog> getLogsByAdminId(Long adminId) {
        return auditLogMapper.selectByAdminId(adminId);
    }

    @Override
    public List<AuditLog> getLogsByTarget(String targetType, Long targetId) {
        return auditLogMapper.selectByTarget(targetType, targetId);
    }

    @Override
    public Integer countByAction(String action, LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogMapper.countByAction(action, startTime, endTime);
    }

    @Override
    @Transactional
    public void cleanOldLogs(Integer days) {
        if (days == null || days <= 0) {
            days = 90; // 默认清理90天前的日志
        }
        LocalDateTime beforeDate = LocalDateTime.now().minusDays(days);
        auditLogMapper.deleteBeforeDate(beforeDate);
        log.info("清理{}天前的审计日志成功", days);
    }

    /**
     * 获取客户端真实IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }
}

